package com.example.clientmiviamoviego4;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

import android.app.ActionBar;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

/**
 * Activity che gestisce la visualizzazione di una lista di film.
 * 
 * @author Gang of Four
 * */
public class ViewListFilmFragmentActivity extends FragmentActivity {

	/**
	 * Campo indicante il numero di film da visualizzare in una singola pagina.
	 * */
	private static final int NUM_PAGED_FILM = 5;
	/**
	 * Campo indicante il numero di film da richiedere all'atto di una richiesta
	 * al server.
	 * */
	private static final int NUM_FILM_REQUEST = 15;
	/**
	 * Riferimento al menu visualizzato all'interno dell'activity.
	 * */
	private Menu menu;
	/**
	 * Riferimento alla singola pagina visualizzata.
	 * */
	private ViewPager mPager;
	/**
	 * Riferimento all'adapter utilizzato per visualizzare ogni singola pagina,
	 * nella fattispecie uno ScreenSlidePagerAdapter.
	 * */
	private PagerAdapter mPagerAdapter;
	/**
	 * ArrayList di ParcelableMovie nella quale e' contenuta la lista di film
	 * completa, aggiornata di volta in volta quando si fanno piu' richieste
	 * consecutive al server.
	 * */
	private ArrayList<ParcelableMovie> completeList;
	/**
	 * ArrayList di ParcelableMovie nella quale e' contenuta la lista di film da
	 * visualizzare in una singola pagina.
	 * */
	private ArrayList<ParcelableMovie> listGUI;
	/**
	 * Stringa indicante l'URL relativo all'indirizzo IP del server.
	 * */
	private String basePath;
	/**
	 * Stringa indicante l'username dell'utente che sta attualmente utilizzando
	 * l'app.
	 * */
	private String user;
	/**
	 * Intero indicante il numero corrente della pagina visualizzata.
	 * */
	private int currentPage;
	/**
	 * Booleano indicante se la presente activity e' stata lanciata dalla
	 * SearchFragment o meno.
	 * */
	private boolean isFilmSearch;
	/**
	 * ArrayList di ParcelableMovieType contenente la lista di generi di film
	 * selezionata dall'utente.
	 * */
	private ArrayList<ParcelableMovieType> selectedPrefs;
	/**
	 * Stringa contenente la data di inizio del range di ricerca.
	 * */
	private String startDate;
	/**
	 * Stringa contenente la data di fine del range di ricerca.
	 * */
	private String endDate;
	/**
	 * Stringa contenente il titolo del film da ricercare.
	 * */
	private String title;
	/**
	 * Stringa contenente il nome del regista da ricercare.
	 * */
	private String director;
	/**
	 * Stringa contenente il nome dell'attore da ricercare.
	 * */
	private String actor;
	/**
	 * Codice della risposta HTTP ricevuta dal server.
	 * */
	private Integer result;

	/**
	 * Metodo richiamato quando l'activity viene creata per la prima volta.
	 * Gestisce lo scambio di informazioni tra l'activity o il fragment che ha
	 * richiamato la ViewListFilmFragmentActivity.
	 * */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_screen_slide);

		Intent intent = getIntent();
		basePath = intent.getStringExtra("basePath");

		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(ViewListFilmFragmentActivity.this);
		user = prefs.getString("username", null);

		isFilmSearch = getIntent().getBooleanExtra("isFilmSearch", false);
		selectedPrefs = intent.getParcelableArrayListExtra("selectedPrefs");

		if (isFilmSearch) {
			selectedPrefs = intent.getParcelableArrayListExtra("selectedPrefs");
			startDate = intent.getStringExtra("startDate");
			endDate = intent.getStringExtra("endDate");
			title = intent.getStringExtra("title");
			director = intent.getStringExtra("director");
			actor = intent.getStringExtra("actor");
		}

		currentPage = 0;

		completeList = new ArrayList<ParcelableMovie>();

		try {
			result = new LongOperation().execute().get();

			if (result == 409) {
				Toast toast = Toast.makeText(this,
						getResources().getString(R.string.index_error),
						Toast.LENGTH_SHORT);
				toast.show();
				finish();
			} else if (result == 416) {
				Toast toast = Toast.makeText(
						this,
						getResources().getString(
								R.string.parameters_not_correct),
						Toast.LENGTH_SHORT);
				toast.show();
				finish();
			} else if (result == -1) {
				Toast toast = Toast.makeText(this,
						getResources().getString(R.string.server_error),
						Toast.LENGTH_SHORT);
				toast.show();
				finish();
			} else if (result == -2){
				Toast toast = Toast.makeText(this,
						getResources().getString(R.string.emptyListViewMessage),
						Toast.LENGTH_SHORT);
				toast.show();
				finish();
			}else if ((completeList.isEmpty() && result == 200 || completeList.isEmpty()
					&& result == 259) ||( completeList.isEmpty() && result != -2)) {
				Toast toast = Toast.makeText(getApplicationContext(),
						R.string.emptyListViewMessage, Toast.LENGTH_SHORT);
				toast.show();
			}
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		mPager = (ViewPager) findViewById(R.id.pager);
		mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
		mPager.setAdapter(mPagerAdapter);
		mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
			@Override
			public void onPageSelected(int position) {
				invalidateOptionsMenu();
			}
		});
		ActionBar actionBar = getActionBar();
		actionBar.setTitle(R.string.title_movie_list);

	}

	/**
	 * Metodo richiamato all'atto della creazione delle voci del menu.
	 * */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		this.menu = menu;
		getMenuInflater().inflate(R.menu.activity_screen_slide, menu);

		menu.findItem(R.id.action_previous).setEnabled(
				mPager.getCurrentItem() > 0);

		MenuItem item = null;
		if (mPager.getCurrentItem() == mPagerAdapter.getCount() - 1
				&& result != 259) {
			item = menu.add(Menu.NONE, R.id.action_next, Menu.NONE,
					R.string.action_viewMore);

		} else if (mPager.getCurrentItem() == mPagerAdapter.getCount() - 1
				&& result == 259 || completeList.isEmpty()) {
			item = menu.add(Menu.NONE, R.id.action_next, Menu.NONE,
					R.string.action_finish);
			menu.findItem(R.id.action_next).setEnabled(false);
		} else {
			item = menu.add(Menu.NONE, R.id.action_next, Menu.NONE,
					R.string.action_next);
		}

		item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
				| MenuItem.SHOW_AS_ACTION_WITH_TEXT);
		return true;
	}

	/**
	 * Metodo richiamato quando un pulsante del menu viene premuto.
	 * */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			finish();
			return true;

		case R.id.action_previous:

			mPager.setCurrentItem(mPager.getCurrentItem() - 1);
			return true;

		case R.id.action_next:

			if (mPager.getCurrentItem() == mPagerAdapter.getCount() - 1) {
				currentPage = mPager.getCurrentItem() + 1;

				if ((currentPage) % 3 == 0) {
					try {
						result = new LongOperation().execute().get();

						if (result == 409) {
							Toast toast = Toast.makeText(this, getResources()
									.getString(R.string.index_error),
									Toast.LENGTH_SHORT);
							toast.show();
							finish();
						} else if (result == 416) {
							Toast toast = Toast.makeText(
									this,
									getResources().getString(
											R.string.parameters_not_correct),
									Toast.LENGTH_SHORT);
							toast.show();
							finish();
						} else if (result == -1) {
							Toast toast = Toast.makeText(this, getResources()
									.getString(R.string.server_error),
									Toast.LENGTH_SHORT);
							toast.show();
							finish();
						}
					} catch (InterruptedException | ExecutionException e) {
						e.printStackTrace();
					}

				}

				mPager = (ViewPager) findViewById(R.id.pager);
				mPagerAdapter = new ScreenSlidePagerAdapter(
						getSupportFragmentManager());
				mPager.setAdapter(mPagerAdapter);
				mPager.setCurrentItem(currentPage);
				mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
					@Override
					public void onPageSelected(int position) {
						invalidateOptionsMenu();
					}
				});

				menu.removeItem(R.id.action_next);
				MenuItem it = menu.add(Menu.NONE, R.id.action_next, Menu.NONE,
						R.string.action_next);
				menu.findItem(R.id.action_previous).setEnabled(false);
				it.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
						| MenuItem.SHOW_AS_ACTION_WITH_TEXT);
			} else {
				mPager.setCurrentItem(mPager.getCurrentItem() + 1);
			}

			return true;
		}

		return super.onOptionsItemSelected(item);
	}

	/**
	 * Classe richiamata ogni volta che si vuole effettuare una richiesta di
	 * nuovi film al server. Viene gestito sia il caso di richesta di film in
	 * caso di ricerca (dati degli specifici campi), sia il caso di
	 * visualizzazione dei film in base alle preferenze settate precedentemente
	 * dall'utente.
	 * */
	private class LongOperation extends AsyncTask<String, Void, Integer> {
		/**
		 * Dialog visualizzato in attesa del compimento delle operazioni in
		 * background.
		 * */
		private ProgressDialog dialog = new ProgressDialog(
				ViewListFilmFragmentActivity.this);
		/**
		 * Codice della risposta HTTP ricevuta dal server.
		 * */
		private int errorMessage;

		/**
		 * Metodo che viene richiamato prima della chiamata a
		 * doInBackground(Params...)
		 * */
		protected void onPreExecute() {
			super.onPreExecute();
			dialog.setMessage(getResources().getString(R.string.wait));
			dialog.show();
			dialog.setCancelable(false);
		}

		/**
		 * Metodo che fa la chiamata al server in background, e attende la
		 * risposta
		 * */
		protected Integer doInBackground(String... urls) {

			HandleConnection connectionRequest;
			if (isFilmSearch) {
				StringBuilder result = new StringBuilder();

				result.append("MiviaMovieServer/rest/movies?");

				if (selectedPrefs.size() != 0) {
					for (ParcelableMovieType singleType : selectedPrefs) {
						result.append("movieType=");
						result.append(singleType.getKey());
						result.append("&");
					}
				}

				result.append("&startDate=");
				result.append(startDate);
				result.append("&endDate=");
				result.append(endDate);
				result.append("&startIndex=");
				result.append(((currentPage) * NUM_PAGED_FILM));
				result.append("&length=");
				result.append(NUM_FILM_REQUEST);

				result.append("&title=");
				result.append(title);
				result.append("&director=");
				result.append(director);
				result.append("&actor=");
				result.append(actor);

				String parameters = result.toString();
				String newString = parameters.replace(" ", "%20");

				connectionRequest = new HandleConnection(basePath, newString,
						OperationEnum.GET_SEARCH_MOVIES);
			} else {
				connectionRequest = new HandleConnection(basePath,
						"MiviaMovieServer/rest/users/" + user
								+ "/movies?startIndex="
								+ ((currentPage) * NUM_PAGED_FILM) + "&length="
								+ NUM_FILM_REQUEST,
						OperationEnum.GET_USER_MOVIES);
			}

			errorMessage = connectionRequest.doGet();
			
			ArrayList<ParcelableMovie> toAppend = (ArrayList<ParcelableMovie>) connectionRequest
					.getArrayList();
			for (int i = 0; i < toAppend.size(); i++) {
				completeList.add(toAppend.get(i));
			}

			return errorMessage;

		}

		/**
		 * Metodo che viene richiamato dopo la chiamata a
		 * doInBackground(Params...)
		 * */
		protected void onPostExecute(Integer unused) {
			dialog.dismiss();
		}
	}

	/**
	 * Classe che gestisce lo slide da una pagina all'altra della
	 * ViewListFilmFragmentActivity.
	 * */
	private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {

		/**
		 * Costruttore della classe ScreenSlidePagerAdapter.
		 * */
		public ScreenSlidePagerAdapter(FragmentManager fm) {
			super(fm);
		}

		/**
		 * Metodo richiamato quando viene cambiata pagina. Vengono presi i film
		 * da visualizzare (nel numero specificato da NUM_PAGED_FILM), per poi
		 * lanciare il fragment ScreenSlidePageFragment associato.
		 * */
		@Override
		public Fragment getItem(int position) {
			listGUI = new ArrayList<ParcelableMovie>();

			for (int i = position * NUM_PAGED_FILM; i < (position + 1)
					* NUM_PAGED_FILM; i++) {
				if (completeList.size() > i) {
					listGUI.add(new ParcelableMovie(
							completeList.get(i).getId(), completeList.get(i)
									.getTitle(), completeList.get(i).getDate(),
							completeList.get(i).getThumbnailURL()));
				}
			}

			return ScreenSlidePageFragment.create(listGUI, basePath);
		}

		/**
		 * Metodo che ottiene il numero di pagina correntemente selezionato
		 * all'interno della ViewListFilmFragmentActivity.
		 * */
		@Override
		public int getCount() {
			if (completeList.size() % NUM_PAGED_FILM == 0) {
				return completeList.size() / NUM_PAGED_FILM;
			} else {
				return ((int) (completeList.size() / NUM_PAGED_FILM)) + 1;
			}
		}

	}

}